package com.lzh.crypt.util;

import com.lzh.crypt.enums.CryptAlgorithmEnum;
import com.lzh.crypt.enums.SignAlgorithmEnum;
import com.lzh.crypt.exception.ErrorCode;
import com.lzh.crypt.exception.RSAException;
import com.lzh.crypt.rsa.RSAKeyPair;
import com.lzh.crypt.rsa.RSAPrivateKeyPair;
import com.lzh.crypt.rsa.RSAPublicKeyPair;
import org.apache.commons.codec.binary.Base64;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * @author zhehen.lu
 * @date 2025/8/10 19:54
 */
public class RSAUtils {

    /**
     * 创建一个RSA密钥对，随机产生
     * @param
     * @return {@link RSAKeyPair}
     * @date 2025/8/10 14:31
     * @author zhehen.lu
     */
    public static RSAKeyPair createRSAKeyPair() {
        return RSAKeyPair.getInstance();
    }

    /**
     * 创建一个密钥对，规定加密方式与验证方式
     * @param cryptAlgorithmEnum
     * @param signAlgorithmEnum
     * @return {@link RSAKeyPair}
     * @date 2025/8/10 14:31
     * @author zhehen.lu
     */
    public static RSAKeyPair createRSAKeyPair(CryptAlgorithmEnum cryptAlgorithmEnum, SignAlgorithmEnum signAlgorithmEnum) {
        return RSAKeyPair.getInstance(cryptAlgorithmEnum.getAlgorithm(), signAlgorithmEnum.getSignType());
    }

    /**
     * 根据公钥与私钥产生一个密钥对
     * @param publicKey
     * @param privateKey
     * @return {@link RSAKeyPair}
     * @date 2025/8/10 14:31
     * @author zhehen.lu
     */
    public static RSAKeyPair createRSAKeyPair(String publicKey, String privateKey) {
        try {
            return new RSAKeyPair(privateKey, publicKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据公钥与私钥产生一个密钥对
     * @param publicKey
     * @param privateKey
     * @param cryptAlgorithmEnum
     * @param signAlgorithmEnum
     * @return {@link RSAKeyPair}
     * @date 2025/8/10 14:31
     * @author zhehen.lu
     */
    public static RSAKeyPair createRSAKeyPair(String publicKey, String privateKey, CryptAlgorithmEnum cryptAlgorithmEnum,
                                              SignAlgorithmEnum signAlgorithmEnum) {
        try {
            return new RSAKeyPair(privateKey, publicKey, cryptAlgorithmEnum.getAlgorithm(), signAlgorithmEnum.getSignType());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公钥加密
     * @param keyPair
     * @param data
     * @return {@link String}
     * @date 2025/8/10 14:30
     * @author zhehen.lu
     */
    public static String encrypt(RSAKeyPair keyPair, String data) {
        byte[] dataByte = data.getBytes(StandardCharsets.UTF_8);
        if (dataByte.length > 245) {
            throw new RSAException(ErrorCode.DATA_TOO_LONG);
        }
        return Base64.encodeBase64String(keyPair.encrypt(dataByte));
    }

    /**
     * 公钥加密
     * @param publicKeyPair
     * @param data
     * @return {@link String}
     * @date 2025/8/10 14:30
     * @author zhehen.lu
     */
    public static String encrypt(RSAPublicKeyPair publicKeyPair, String data) {
        byte[] dataByte = data.getBytes(StandardCharsets.UTF_8);
        if (dataByte.length > 245) {
            throw new RSAException(ErrorCode.DATA_TOO_LONG);
        }
        return Base64.encodeBase64String(publicKeyPair.encrypt(dataByte));
    }

    /**
     * 私钥加密
     * @param rsaKeyPair
     * @param data
     * @return {@link String}
     * @date 2025/8/10 14:30
     * @author zhehen.lu
     */
    public static String encryptByPrivateKey(RSAKeyPair rsaKeyPair, String data) {
        byte[] dataByte = data.getBytes(StandardCharsets.UTF_8);
        if (dataByte.length > 245) {
            throw new RSAException(ErrorCode.DATA_TOO_LONG);
        }
        return Base64.encodeBase64String(rsaKeyPair.encryptByPrivateKey(dataByte));
    }

    /**
     * 私钥加密
     * @param privateKeyPair
     * @param data
     * @return {@link String}
     * @date 2025/8/10 14:30
     * @author zhehen.lu
     */
    public static String encryptByPrivateKey(RSAPrivateKeyPair privateKeyPair, String data) {
        byte[] dataByte = data.getBytes(StandardCharsets.UTF_8);
        if (dataByte.length > 245) {
            throw new RSAException(ErrorCode.DATA_TOO_LONG);
        }
        return Base64.encodeBase64String(privateKeyPair.encrypt(dataByte));
    }

    /**
     * 私钥解密
     * @param keyPair
     * @param data
     * @return {@link String}
     * @date 2025/8/10 14:30
     * @author zhehen.lu
     */
    public static String decrypt(RSAKeyPair keyPair, String data) {
        byte[] dataByte = Base64.decodeBase64(data);
        byte[] decryptByte = keyPair.decypt(dataByte);
        return new String(decryptByte, StandardCharsets.UTF_8);
    }

    /**
     * 私钥解密
     * @param privateKeyPair
     * @param data
     * @return {@link String}
     * @date 2025/8/10 14:30
     * @author zhehen.lu
     */
    public static String decrypt(RSAPrivateKeyPair privateKeyPair, String data) {
        byte[] dataByte = Base64.decodeBase64(data);
        byte[] decryptByte = privateKeyPair.decypt(dataByte);
        return new String(decryptByte, StandardCharsets.UTF_8);
    }

    /**
     * 公钥解密
     * @param keyPair
     * @param data
     * @return {@link String}
     * @date 2025/8/10 14:30
     * @author zhehen.lu
     */
    public static String decryptByPublicKey(RSAKeyPair keyPair, String data) {
        byte[] dataByte = Base64.decodeBase64(data);
        byte[] decryptByte = keyPair.decyptByPublicKey(dataByte);
        return new String(decryptByte, StandardCharsets.UTF_8);
    }

    /**
     * 公钥解密
     * @param rsaPublicKeyPair
     * @param data
     * @return {@link String}
     * @date 2025/8/10 14:30
     * @author zhehen.lu
     */
    public static String decryptByPublicKey(RSAPublicKeyPair rsaPublicKeyPair, String data) {
        byte[] dataByte = Base64.decodeBase64(data);
        byte[] decryptByte = rsaPublicKeyPair.decypt(dataByte);
        return new String(decryptByte, StandardCharsets.UTF_8);
    }

    /**
     * 公钥加密生成签名
     * @param keyPair
     * @param data
     * @return {@link String}
     * @date 2025/8/10 14:30
     * @author zhehen.lu
     */
    public static String sign(RSAKeyPair keyPair, String data) {
        byte[] sign = keyPair.sign(data.getBytes(StandardCharsets.UTF_8));
        return Base64.encodeBase64String(sign);
    }

    /**
     * 私钥加密生成签名
     * @param rsaPrivateKeyPair
     * @param data
     * @return {@link String}
     * @date 2025/8/10 14:30
     * @author zhehen.lu
     */
    public static String sign(RSAPrivateKeyPair rsaPrivateKeyPair, String data) {
        byte[] sign = rsaPrivateKeyPair.sign(data.getBytes(StandardCharsets.UTF_8));
        return Base64.encodeBase64String(sign);
    }

    /**
     * 根据数据与签名验证公钥正确性
     * @param keyPair
     * @param data
     * @param sign
     * @return {@link boolean}
     * @date 2025/8/10 14:29
     * @author zhehen.lu
     */
    public static boolean verify(RSAKeyPair keyPair, String data, String sign) {
        byte[] signByte = Base64.decodeBase64(sign);
        byte[] dataByte = data.getBytes(StandardCharsets.UTF_8);
        return keyPair.verifyPublicKey(dataByte, signByte);
    }

    /**
     * 根据数据与签名验证公钥正确性
     * @param keyPair
     * @param data
     * @param sign
     * @return {@link boolean}
     * @date 2025/8/10 14:29
     * @author zhehen.lu
     */
    public static boolean verify(RSAPublicKeyPair keyPair, String data, String sign) {
        byte[] signByte = Base64.decodeBase64(sign);
        byte[] dataByte = data.getBytes(StandardCharsets.UTF_8);
        return keyPair.verifyPublicKey(dataByte, signByte);
    }
}
